//<start id="java_contextualHibernateDao"/> 
package com.vonzhou.spitter.persistence;

import com.vonzhou.spitter.domain.Spitter;
import com.vonzhou.spitter.domain.Spittle;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

/**
 * @author XiaoDongLei
 * @Package com.vonzhou.springinaction.knights
 * @date 2018/4/1
 * @Description: 构建不依赖于Spring的Hibernate代码
 * <p>
 * 1、保证每个事务使用同一个Session
 * <p>
 * 在Spring和Hibernate的早期岁月中，编写Repository类将会涉及到使用Spring的HibernateTemplate。HibernateTemplate能够保证每个事务使用同一个Session。但是这种方式的弊端在于我们的Repository实现会直接与Spring耦合。
 * <p>
 * 现在的最佳实践是不再使用HibernateTemplate，而是使用上下文Session（Contextual session）。通过这种方式，会直接将Hibernate SessionFactory装配到Repository中，并使用它来获取Session，如下面的程序清单所示。
 * <p>
 * 2、另外需要注意的是，我们在类上使用了@Repository注解，这会为我们做两件事情。首先，@Repository是Spring的另一种构造性注解，它能够像其他注解一样被Spring的组件扫描所扫描到。这样就不必明确声明HibernateSpitterRepository bean了，只要这个Repository类在组件扫描所涵盖的包中即可。
 * <p>
 * 除了帮助减少显式配置以外，@Repository还有另外一个用处。让我们回想一下模板类，它有一项任务就是捕获平台相关的异常，然后使用Spring统一非检查型异常的形式重新抛出。如果我们使用Hibernate上下文Session而不是Hibernate模板的话，那异常转换会怎么处理呢？
 * <p>
 * 为了给不使用模板的Hibernate Repository添加异常转换功能，我们只需在Spring应用上下文中添加一个PersistenceExceptionTranslationPostProcessor bean，这个bean是后置处理器（bean post-processor），它会在所有拥有@Repository注解的类上添加一个通知器（advisor），这样就会捕获任何平台相关的异常并以Spring非检查型数据访问异常的形式重新抛出。
 * <p>
 * 给使用@Repository的类，并且单独使用的Hibernate上下文Session的类，将Hibernate中抛出的异常交给Spring重新抛出。
 */
@Repository
@Transactional
public class HibernateSpitterDao implements SpitterDao {
	private SessionFactory sessionFactory;

	@Autowired
	public HibernateSpitterDao(SessionFactory sessionFactory) {
		//<co id="co_injectSessionFactory"/>
		this.sessionFactory = sessionFactory;
	}

	private Session currentSession() {
		//<co id="co_getCurrentSession"/>
		return sessionFactory.getCurrentSession();
	}

	@Override
	public void addSpitter(Spitter spitter) {
		//<co id="co_useSession"/>
		currentSession().save(spitter);
	}

	@Override
	public Spitter getSpitterById(long id) {
		//<co id="co_useSession"/>
		return currentSession().get(Spitter.class, id);
	}

	@Override
	public void saveSpitter(Spitter spitter) {
		//<co id="co_useSession"/>
		currentSession().update(spitter);
	}
	//<end id="java_contextualHibernateDao"/>

	@Override
	public List<Spittle> getRecentSpittle() {
		//  return currentSession().f  loadAll(Spittle.class); // this isn't right...just a placeholder for now
		return null;
	}

	@Override
	public void saveSpittle(Spittle spittle) {
		currentSession().save(spittle);
	}

	@Override
	public List<Spittle> getSpittlesForSpitter(
			Spitter spitter) {

		return null;
	}

	@Override
	public Spitter getSpitterByUsername(String username) {

		return null;
	}

	@Override
	public void deleteSpittle(long id) {
		currentSession().delete(getSpittleById(id));
	}

	@Override
	public Spittle getSpittleById(long id) {
		return currentSession().get(Spittle.class, id);
	}

	@Override
	public List<Spitter> findAllSpitters() {

		return null;
	}
}